﻿using System;
using System.Collections.Generic;
using XNOgre.Graphics;
using Microsoft.Xna.Framework;

namespace XNOgre.Core
{
    public class SubEntity : IRenderable
    {
        private bool visible;
        private RenderOperation renderOp;

        internal SubEntity()
        {
            this.visible = true;
        }
        public Material Material
        {
            get;
            set;
        }
        public RenderOperation RenderOperation
        {
            get { return renderOp; }
            internal set { renderOp = value; }
        }

        public Entity Parent
        {
            get;
            internal set;
        }
        public BoundingBox BoundingBox
        {
            get;set;
        }
        public bool Visible
        {
            get { return visible; }
            set { visible = value; }
        }
        //overridden from Entity, shouldn't be called directly
        public Microsoft.Xna.Framework.Matrix WorldTransforms
        {
            get { return BoneTransforms * Parent.WorldTransforms; }
        }
        public Microsoft.Xna.Framework.Matrix BoneTransforms { get; internal set; }
        public bool CastsShadows
        {
            get { return true; }
        }

        public bool ReceiveShadows
        {
            get { return true; }
        }

        public RenderQueueGroupID RenderQueueGroup
        {
            get { return Parent.RenderQueueGroup; }
        }

        public IEnumerable<Light> Lights
        {
            get
            {
                return Parent.Lights;
            }
            set
            {
                Parent.Lights = value;
            }
        }

        internal void UpdateBoundingBox()
        {
            int stride = this.renderOp.VertexData.VertexDeclaration.VertexStride;
            int numVerts = this.renderOp.VertexCount;

            byte[] data = new byte[stride * numVerts];

            renderOp.VertexData.GetData<byte>(data);

            Vector3 max = Vector3.Zero;
            Vector3 min = Vector3.Zero;

            for (int ndx = 0; ndx < data.Length; ndx += stride)
            {
                float x = BitConverter.ToSingle(data, ndx);
                float y = BitConverter.ToSingle(data, ndx + 4);
                float z = BitConverter.ToSingle(data, ndx + 8);

                Vector3 currentVertex = new Vector3(x, y, z);
                Vector3 worldVertex = Vector3.Transform(currentVertex, WorldTransforms);

                if (worldVertex.X < min.X)
                    min.X = worldVertex.X;

                if (worldVertex.Y < min.Y)
                    min.Y = worldVertex.Y;

                if (worldVertex.Z < min.Z)
                    min.Z = worldVertex.Z;

                if (worldVertex.X > max.X)
                    max.X = worldVertex.X;

                if (worldVertex.Y > max.Y)
                    max.Y = worldVertex.Y;

                if (worldVertex.Z > max.Z)
                    max.Z = worldVertex.Z;
            }

            BoundingBox = new BoundingBox(min, max);
        }
        public float GetSquaredViewDepth(Camera camera)
        {
            float distance = Microsoft.Xna.Framework.Vector3.Distance(Parent.ParentNode.DerivedPosition, camera.DerivedPosition);
            return distance * distance;
        }
    }
}
